package pri.damai.xiaowu.gateway.handler;

import com.alibaba.fastjson.JSONObject;
import pri.damai.xiaowu.common.core.exception.GlobalException;
import pri.damai.xiaowu.common.core.vo.ResultVO;
import pri.damai.xiaowu.gateway.enums.GatewayResultEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 网关通用异常处理器
 * @Desc 只作用在webflux下
 * @Author DaMai
 * @Date 2021/4/1 10:54
 * 但行好事，莫问前程。
 */
@Slf4j
@Order(-1)
@Component
@RequiredArgsConstructor
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {

        log.info("gateway 异常拦截。{}",throwable.fillInStackTrace().toString());

        ServerHttpResponse response = exchange.getResponse();
        if (response.isCommitted()) {
            return Mono.error(throwable);
        }

        // 设置请求头
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.getHeaders().setAccessControlAllowOrigin("*");
        if (throwable instanceof ResponseStatusException) {
            response.setStatusCode(HttpStatus.OK);
        }

        String code = GatewayResultEnum.GATEWAY_SYS_ERROR.code();
        String msg = GatewayResultEnum.GATEWAY_SYS_ERROR.desc();
        if (!StringUtils.isBlank(throwable.getMessage())) {
            msg = throwable.getMessage();
        }
        DataBufferFactory bufferFactory = response.bufferFactory();
        if (throwable instanceof GlobalException) {
            GlobalException exception = (GlobalException) throwable;
            code = exception.getCode();
            msg = exception.getMsg();
        }

        final String finalCode = code;
        final String finalMsg = msg;
        return response.writeWith(Mono.fromSupplier(() -> bufferFactory.wrap(JSONObject.toJSONBytes(ResultVO.error(finalCode, finalMsg)))
        ));
    }
}
